// Copyright 2007 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package lichen.internal.services;

import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import lichen.entities.user.FriendList;
import lichen.entities.user.OnlineUser;
import lichen.entities.user.User;
import lichen.services.Encoder;
import lichen.services.InvalidateUserException;
import lichen.services.ServiceMessages;
import lichen.services.UserService;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.tapestry5.services.Cookies;
import org.apache.tapestry5.services.RequestGlobals;
import org.hibernate.id.UUIDHexGenerator;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.transaction.annotation.Transactional;

/**
 * 用户操作的实现类.
 * @author jcai
 * @version $Revision: 225 $
 * @since 0.0.1
 */
@Transactional
public class UserServiceImpl implements UserService{
	/**
	 * Logger for this class
	 */
	private static final Log logger = LogFactory.getLog(UserServiceImpl.class);
	
	
	
	/** 更新用户的信息 **/
	private static final String LOGIN_UPDATE_ONLINE_USER_HQL="update "+OnlineUser.class.getName()+" u  set " +
	"u."+OnlineUser.NICK_NAME_PRO_NAME+"=?, " +
	"u."+OnlineUser.SECURITY_CODE_PRO_NAME+"=?, " +
	"u."+OnlineUser.USER_PRO_NAME+"=?," +
	"u."+OnlineUser.LAST_ACTIVE_CONTENT_PRO_NAME+"=? , " +
			"u."+OnlineUser.LAST_ACTIVE_TIME_PRO_NAME+"=? " +
					"where u."+OnlineUser.SECURITY_CODE_PRO_NAME+"=?";
	/** 更新匿名用户的信息 **/
	private static final String UPDATE_ONLINE_ANONYMOUS_INFO_HQL="update "+OnlineUser.class.getName()+" u  set " +
	"u."+OnlineUser.LAST_ACTIVE_CONTENT_PRO_NAME+"=? , " +
			"u."+OnlineUser.LAST_ACTIVE_TIME_PRO_NAME+"=? " +
					"where u."+OnlineUser.SECURITY_CODE_PRO_NAME+"=? ";

	/** 更新已经登录用户的信息 **/
	private static final String UPDATE_ONLINE_USER_INFO_HQL=UPDATE_ONLINE_ANONYMOUS_INFO_HQL+" and " +
							"u."+OnlineUser.USER_PRO_NAME+"=?";
	
	
	/** 记录用户的安全码的cookie名字 **/
	private static final String LICHEN_USER_SECURITY_CODE_COOKIE_NAME = "lusc";
	/** 记录用户ID的安全吗的cookie名字 **/
	public static final String LICHEN_USER_ID_COOKIE_NAME = "lunc";
	/** 记录用户当前的nickName **/
	private static final String LICHEN_USER_NICK_NAME_COOKIE_NAME = "lunn";

	

	private static UUIDHexGenerator GENERATOR=new UUIDHexGenerator();
	

	
	private Cookies _cookies;

	
	/**
	 * @see lichen.services.UserService#saveRegisterUser(lichen.entities.user.User)
	 * @since 0.0.3
	 */
	public void registerUser(User user,String plainPassword){
		user.addRole("ROLE_USER");//注册用户默认带有普通用户权限
		this._template.save(user);
//		try {
//			loginUser(user.getEmail(),plainPassword);
//		} catch (InvalidateUserException e) {
//			throw new RuntimeException(e);
//		}
	}
	

	private RequestGlobals _requestGlobals;

	private HibernateTemplate _template;



	private Encoder _encoder;

	public UserServiceImpl(RequestGlobals requestGlobals,Cookies cookies,HibernateTemplate template,Encoder encoder){
		this._cookies = cookies;
		
		_requestGlobals = requestGlobals;
		_template = template;
		_encoder = encoder;
	}
	
	/**
	 * @see lichen.services.UserService#activeOnlineUser(java.lang.String)
	 */
	public void activeOnlineUser(String activeContent) {
		String oldSecurityCode = _cookies.readCookieValue(LICHEN_USER_SECURITY_CODE_COOKIE_NAME);
		String uid =  _cookies.readCookieValue(LICHEN_USER_ID_COOKIE_NAME);
		//当前时间
		long currentTime = new Date().getTime();
		//判断是否存在在线的用户
		boolean existUser = false;
		if(oldSecurityCode != null){
			List<Object> parameters = new ArrayList<Object>();
			parameters.add(activeContent);
			parameters.add(currentTime);
			parameters.add(oldSecurityCode);
			if(uid != null ){
				parameters.add(User.newInstance(uid));
			}
			int rows = _template.bulkUpdate(uid==null?UPDATE_ONLINE_ANONYMOUS_INFO_HQL:UPDATE_ONLINE_USER_INFO_HQL, 
					parameters.toArray());
			
			

			if (logger.isDebugEnabled()) {
				logger.debug("get online user count ["+rows+"]"); //$NON-NLS-1$
			}

			existUser = rows ==1;
		}
		if(! existUser){
			//得到一个新的加密码
			String securityCode = createNewSecurityCode();
			createOnlineUser(null,securityCode,currentTime,activeContent);
			//--------------- 对客户端的cookie进行处理
			_cookies.removeCookieValue(LICHEN_USER_ID_COOKIE_NAME);
			_cookies.writeCookieValue(LICHEN_USER_SECURITY_CODE_COOKIE_NAME, securityCode);

		}

	}

	/**
	 * @see lichen.services.UserService#isSystemUser()
	 */
	public boolean isSystemUser() {
		String oldSecurityCode = _cookies.readCookieValue(LICHEN_USER_SECURITY_CODE_COOKIE_NAME);
		String uid =  _cookies.readCookieValue(LICHEN_USER_ID_COOKIE_NAME);
		if(oldSecurityCode == null ||uid == null){
			return false;
		}
		
		long count=(Long) _template.findByNamedQuery(OnlineUser.QUERY_LOGIN_SYSTEM_USER_NAMED_QUERY, 
				new Object[]{User.newInstance(uid),oldSecurityCode}).iterator().next();
		
		return count == 1;
	}

	/**
	 * @see lichen.services.UserService#loginUser(java.lang.String, java.lang.String)
	 */
	public void loginUser(String userEmail, String password) throws InvalidateUserException {
		Iterator it = _template.findByNamedQuery(User.CHECK_USER_HQL_NAMED_QUERY,new Object[]{userEmail,_encoder.encodPassword(password)}).iterator();
		
		
		if(!it.hasNext()){
			throw new InvalidateUserException(ServiceMessages.invlidateUserLogin());
		}
		User user=(User) it.next();
		
		//得到一个新的加密码
		String securityCode = createNewSecurityCode();
		//当前时间
		long currentTime = new Date().getTime();
		//---------------- 通过老的安全码来更新数据库
		String oldSecurityCode = _cookies.readCookieValue(LICHEN_USER_SECURITY_CODE_COOKIE_NAME);
		boolean existUser = false;
		
		//检查在线用户，如果此人还在线就删除
		checkOnlineUser(user);
		
		if(oldSecurityCode != null ){
			int rows=_template.bulkUpdate(LOGIN_UPDATE_ONLINE_USER_HQL,
					new Object[]{user.getNickName(),securityCode,user,"Login Forum",currentTime,oldSecurityCode});
	
			if (logger.isDebugEnabled()) {
				logger.debug("update exist user "+rows); //$NON-NLS-1$
			}
			existUser = rows >0;
		}
		
		//-------------- 表中为找用户，则进行插入操作
		if(!existUser){
			 createOnlineUser(user,securityCode,currentTime,"Login Forum");
		}
		
		//--------------- 对客户端的cookie进行处理
		_cookies.writeCookieValue(LICHEN_USER_ID_COOKIE_NAME, user.getId());
		_cookies.writeCookieValue(LICHEN_USER_NICK_NAME_COOKIE_NAME, user.getNickName());
		_cookies.writeCookieValue(LICHEN_USER_SECURITY_CODE_COOKIE_NAME, securityCode);
		
		
	}
	
	/**
	 * 检查OnlineUser是否有重复用户
	 * @param user User Object
	 * @since 0.0.3
	 */
	private void checkOnlineUser(User user) {
		Iterator it = _template.findByNamedQuery(OnlineUser.CHECK_ONLINE_USER_NAMED_QUERY,user).iterator();
		if(it.hasNext()){
			OnlineUser onlineUser = (OnlineUser) it.next();
			_template.delete(onlineUser);
		}
	}

	private void createOnlineUser(User user,String securityCode,long currentTime,String activeContent){
		//TODO 处理多线程插入多个相同的uid.
		// 两种方式可以处理，1.方法同步,弊端在,同步块里面还要检查一次.
		//2.捕获数据库异常，弊端，异常不是很好的设计方法.
		OnlineUser onlineUser = new OnlineUser();
		if(user!=null)
			onlineUser.setNickName(user.getNickName());
		else
			onlineUser.setNickName("guest");
		onlineUser.setUser(user);
		onlineUser.setSecurityCode(securityCode);
		onlineUser.setLoginTime(currentTime);
		onlineUser.setLastActiveTime(currentTime);
		onlineUser.setLastActiveContent(activeContent);
		//获得IP地址
		onlineUser.setIpAddress(_requestGlobals.getHTTPServletRequest().getRemoteAddr()); 
		_template.save(onlineUser);
	}
	//产生加密码
	private String createNewSecurityCode(){
		return DigestUtils.md5Hex(GENERATOR.generate(null, null).toString());
	}

	/**
	 * 
	 * @see lichen.services.UserService#getOnlineUserNum()
	 * 
	 */
	public long getOnlineUserNum() {
		//TODO 考虑采用一个全局的静态变量保存当前的在线人数.
		//可以避免每次查询数据库带来的消耗，需要注意的是变量的同步线程调用.
		//在insert时候 +1,在delete时候 -rows
		return (Long)_template.findByNamedQuery(OnlineUser.COUNT_ONLINE_USER_NUM_NAMED_QUERY).iterator().next();
		
	}

	/**
	 * 
	 * @see lichen.services.UserService#isExistEmail(java.lang.String)
	 * @since 0.0.2
	 */
	public boolean isExistEmail(String email) {
		return (Long)_template.findByNamedQuery(User.EXIST_USER_EMAIL_NAMED_QUERY,email).iterator().next()>0;
	}




	/**
	 * @see lichen.services.UserService#delFriendList(java.lang.String)
	 * @since 0.0.3
	 */
	public void delFriendList(String id) {
		FriendList friendList = FriendList.newInstance(id);
		this._template.delete(friendList);
	}
	/**
	 * 得到当前用户
	 * @see lichen.services.UserService#getCurrentUser()
	 * @since 0.0.3
	 */
	public User getCurrentUser() {
		
		if(!isSystemUser()){
			return null;
		}
		
		String uid =  _cookies.readCookieValue(LICHEN_USER_ID_COOKIE_NAME);
		
		return (User) _template.get(User.class, uid);
	}
}
